﻿using System;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Numerics;
using System.Text;
using UtilZ.Dotnet.Ex.Model;

namespace UtilZ.Dotnet.Ex.Base
{
    /// <summary>
    /// 调试辅助类
    /// </summary>
    public class DebugHelper
    {
        private static DebugHelper _default = null;
        /// <summary>
        /// 获取默认调试辅助类对象
        /// </summary>
        public static DebugHelper Default
        {
            get
            {
                if (_default == null)
                {
                    _default = new DebugHelper();
                }

                return _default;
            }
        }




        /// <summary>
        /// 构造函数
        /// </summary>
        public DebugHelper()
        {

        }




        #region 计时

        private readonly Stopwatch _stopwatch = new Stopwatch();

        /// <summary>
        /// 开始计时
        /// </summary>
        public void Start()
        {
            this._stopwatch.Restart();
        }

        /// <summary>
        /// 停止计时
        /// </summary>
        public void Stop()
        {
            this._stopwatch.Stop();
        }

        /// <summary>
        /// 持续时长,单位:毫秒
        /// </summary>
        public double Duration
        {
            get
            {
                return this._stopwatch.Elapsed.TotalMilliseconds;
            }
        }

        #endregion






        #region 数据


        /// <summary>
        /// 调试值字典集合[key:调试值key;value:调试值]
        /// </summary>
        private readonly ConcurrentDictionary<string, object> _debugValueDic = new ConcurrentDictionary<string, object>();
        /// <summary>
        /// 获取调试值字典集合[key:调试值key;value:调试值]
        /// </summary>
        public ConcurrentDictionary<string, object> ObjDic
        {
            get { return _debugValueDic; }
        }

        /// <summary>
        /// 添加调试值
        /// </summary>
        /// <param name="key">调试值key</param>
        /// <param name="value">调试值</param>
        public void Add<T>(string key, T value)
        {
            if (key == null)
            {
                throw new ArgumentNullException(nameof(key));
            }

            if (this._debugValueDic.ContainsKey(key))
            {
                throw new ArgumentException($"重复的Key:{key}");
            }

            if (!this._debugValueDic.TryAdd(key, value))
            {
                throw new ArgumentException($"添加Key:{key}失败");
            }
        }

        /// <summary>
        /// 设置调试值
        /// </summary>
        /// <param name="key">调试值key</param>
        /// <param name="value">调试值</param>
        public void Set<T>(string key, T value)
        {
            if (key == null)
            {
                throw new ArgumentNullException(nameof(key));
            }

            this._debugValueDic[key] = value;
        }

        /// <summary>
        /// 获取调试值
        /// </summary>
        /// <param name="key">调试值key</param>
        /// <returns>调试值</returns>
        public T Get<T>(string key)
        {
            if (key == null)
            {
                throw new ArgumentNullException(nameof(key));
            }

            return (T)this._debugValueDic[key];
        }

        /// <summary>
        /// 尝试获取调试值
        /// </summary>
        /// <param name="key">调试值key</param>
        /// <param name="value">调试值</param>
        /// <returns>获取结果</returns>
        public bool TryGet<T>(string key, out T value)
        {
            if (key == null)
            {
                throw new ArgumentNullException(nameof(key));
            }

            object obj;
            if (this._debugValueDic.TryGetValue(key, out obj))
            {
                value = (T)obj;
                return true;
            }
            else
            {
                value = default(T);
                return false;
            }
        }

        /// <summary>
        /// 移除调试值
        /// </summary>
        /// <param name="key">调试值key</param>
        /// <returns>移除结果</returns>
        public bool Remove(string key)
        {
            if (key == null)
            {
                throw new ArgumentNullException(nameof(key));
            }

            object oldValue;
            return this._debugValueDic.TryRemove(key, out oldValue);
        }

        /// <summary>
        /// 清空调试值
        /// </summary>
        public void Clear()
        {
            this._debugValueDic.Clear();
        }

        #endregion



        #region ToString

        /// <summary>
        /// Span泛型ToString
        /// </summary>
        /// <typeparam name="T">泛型类型</typeparam>
        /// <param name="span">数据</param>
        /// <returns>string</returns>
        public static string ToString<T>(in Span<T> span) where T : struct
        {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < span.Length; i++)
            {
                if (sb.Length > 0)
                {
                    sb.AppendLine();
                }
                sb.Append(span[i].ToString());
            }

            return sb.ToString();
        }

        /// <summary>
        /// SpanZ泛型ToString
        /// </summary>
        /// <typeparam name="T">泛型类型</typeparam>
        /// <param name="span">数据</param>
        /// <returns>string</returns>
        public static string ToString<T>(in SpanZ<T> span) where T : struct
        {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < span.Length; i++)
            {
                if (sb.Length > 0)
                {
                    sb.AppendLine();
                }
                sb.Append(span[i].ToString());
            }

            return sb.ToString();
        }

        /// <summary>
        /// 数组ToString
        /// </summary>
        /// <typeparam name="T">泛型类型</typeparam>
        /// <param name="arr">数组</param>
        /// <returns>string</returns>
        public static string ToString<T>(T[] arr)
        {
            StringBuilder sb = new StringBuilder();

            for (int i = 0; i < arr.Length; i++)
            {
                if (sb.Length > 0)
                {
                    sb.AppendLine();
                }
                sb.Append(arr[i].ToString());
            }

            return sb.ToString();
        }



        /// <summary>
        /// SpanZ Complex ToString
        /// </summary>
        /// <param name="span">数据</param>
        /// <returns>string</returns>
        public static string ToString(in SpanZ<Complex> span)
        {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < span.Length; i++)
            {
                if (sb.Length > 0)
                {
                    sb.AppendLine();
                }
                sb.Append(span[i].Real.ToString());
                sb.Append(',');
                sb.Append(span[i].Imaginary.ToString());
            }
            return sb.ToString();
        }

        /// <summary>
        /// SpanZ Complex 实部ToString
        /// </summary>
        /// <param name="span">数据</param>
        /// <returns>string</returns>
        public static string ToRealString(in SpanZ<Complex> span)
        {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < span.Length; i++)
            {
                if (sb.Length > 0)
                {
                    sb.AppendLine();
                }
                sb.Append(span[i].Real.ToString());
            }
            return sb.ToString();
        }

        /// <summary>
        /// SpanZ Complex虚部ToString
        /// </summary>
        /// <param name="span">数据</param>
        /// <returns>string</returns>
        public static string ToImaginaryString(in SpanZ<Complex> span)
        {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < span.Length; i++)
            {
                if (sb.Length > 0)
                {
                    sb.AppendLine();
                }
                sb.Append(span[i].Imaginary.ToString());
            }
            return sb.ToString();
        }


        /// <summary>
        /// SpanZ double ToString
        /// </summary>
        /// <param name="span">数据</param>
        /// <returns>string</returns>
        public static string ToString(in SpanZ<double> span)
        {
            StringBuilder sb = new StringBuilder();

            for (int i = 0; i < span.Length; i++)
            {
                if (sb.Length > 0)
                {
                    sb.AppendLine();
                }
                sb.Append(span[i].ToString());
            }
            return sb.ToString();
        }

        #endregion


    }



}
